
#ifndef __CRYPTECHAIN_H
#define __CRYPTECHAIN_H

#include "../iface/CryptInterface.h"
#include "../aprtools/APRBucketBrigade.h"
#include "../iface/debug.h"
#include "KeyPair.h"

#include "EncryptionKey.h"
#include "DecryptionKey.h"
#include "SigningKey.h"
#include "CheckingKey.h"

// This was 65536
/** The buffer size for the internal envelope reading buffer */
#define ENV_READ_BUFFER 1114112

//#define DEBUG_CRYPTLIB_OBJECTS 1

/** The structure of a link in the cryptographic envelope chain (CryptEChain).
 * Each link has a buffer associated with it for moving data between
 * consecutive envelopes in the chain. This is for temporarily storing
 * the data in the stream before pushing it into the next envelope
 * along the chain. */
typedef struct crypt_envelope_link
{
   /** The cryptlib specified envelope for stream-based modification
    * (encryption, decryption, signing or checking) of the incoming data. */
   CRYPT_ENVELOPE envelope;
   /** The cryptlib specified cryptography context containing the key. */
   CRYPT_CONTEXT cntxt;
   /** The intent flag gives the intention of the envelope to enable
    * appropriate interjections to add data to the enveloping process. */
   int intent;
   /** The inward pointer gives the previous pointer in the list, the
    * cryptographic envelope that has already been run on the data, or the
    * envelope before this one. */
   struct crypt_envelope_link *inward;
   /** The outward pointer gives the next pointer in the list, the 
    * cryptographic envelope that is about to be run over the data, or the
    * envelope after this one. */
   struct crypt_envelope_link *outward;
   /** The pointer to the buffer associated with this link, which holds data
    * output from this link's envelope before it is pushed into the next
    * envelope in the chain, or popped altogether. */
   char *buf;
   /** The amount of data currently held in this link's buffer, in bytes. */
   int bytesinbuf;
} CryptELink;

/** A wrapper for the creation, storage and processing of cryptography
 * workflows, in the form of a linked list of CryptELink structs containing
 * cryptlib's cryptographic envelopes. These provide an interface for
 * encrypting, decryption, signing, checking, compressing and decompressing
 * streams of data. */
class CryptEChain
{
   public:
      CryptEChain();
      ~CryptEChain();
      int64_t processIteration(APRBucketBrigade *inp, char *dbuffer, int imaxdata);
      int processIteration(APRBucketBrigade *inp, APRBucketBrigade *out);
      void process(APRBucketBrigade *inp, APRBucketBrigade *out);
      void addEnvelope(CRYPT_ENVELOPE nenvelope, CRYPT_CONTEXT icntxt, int iintent);
      static CRYPT_ENVELOPE encodingEnvelope();
      static CRYPT_ENVELOPE decodingEnvelope();
      static CRYPT_ENVELOPE generateCompressEnv();
      static CRYPT_ENVELOPE generateDecompressEnv();
      void buildBasicChain(const char *cname, const char *sname, KeyPair *crypto, KeyPair *signing, int dodecrypt, int docompress);
      void buildBasicChain2(const char *cname, const char *sname, KeyPair *crypto, KeyPair *signing, int dodecrypt, int docompress, int inputsize);
      void buildEncryptionChain2(EncryptionKey *crypto, SigningKey *signing, int docompress, int inputsize);
      void buildDecryptionChain2(DecryptionKey *crypto, CheckingKey *signing, int dodecompress, int inputsize);
      int isTrusted() { return trusted; }
   private:
      int prePushInterjection(CryptELink *clink);
      int postFlushInterjection(CryptELink *clink);
      int prePopInterjection(CryptELink *clink);
      /** Markers for the crypt context to let the cryptographic envelope chain
      * (CryptEChain) know the purpose of each of the links, so that it knows
      * when to interject in the enveloping operations with more data. */
      enum cryptcontexttypes {   CRYPTCONTEXT_USED = 0x00,
                                 CRYPTCONTEXT_PUBLIC_KEY_ENCRYPT = 0x01,
                                 CRYPTCONTEXT_PRIVATE_KEY_DECRYPT = 0x02,
                                 CRYPTCONTEXT_SIGN_PRIVATE_KEY = 0x03,
                                 CRYPTCONTEXT_CHECKSIG_PUBLIC_KEY = 0x04,
                                 CRYPTCONTEXT_COMPRESS = 0x05,
                                 CRYPTCONTEXT_DECOMPRESS = 0x06,
                                 CRYPTCONTEXT_SYMM_KEY_ENCRYPT = 0x07,
                                 CRYPTCONTEXT_SYMM_KEY_DECRYPT = 0x08,
                                 CRYPTCONTEXT_DONEINTERJECTION = 0x10    };
      /** The first or root link in the chain of links containing cryptographic
       * processes. */
      CryptELink *root;
      /** The first buffer for holding data immediately removed from the piped
       * data stream that is input to this class. */
      char *firstbuf;
      /** The number of bytes currently in the first buffer. */
      int firstbib;
      /** A flag to be set when a signature is checked successfully and found
       * to be matching, therefore meaning that the data processed is to be
       * trusted, as it has asserted its identity. */
      int trusted;
};

#endif
